package com.chhuang.uresource.controller;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Date;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.codec.CharEncoding;
import org.apache.commons.httpclient.URI;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSONObject;
import com.chhuang.core.bean.QueryBean;
import com.chhuang.core.validation.ValidGroupSave;
import com.chhuang.uresource.bean.UResourceQueryBean;
import com.chhuang.uresource.conts.SysConstants;
import com.chhuang.uresource.po.UResource;
import com.chhuang.uresource.service.IUResourceService;
import com.chhuang.utils.Assert;
import com.chhuang.utils.config.SysConfig;
import com.chhuang.utils.date.DateUtil;
import com.chhuang.utils.file.FileUtil;

@Controller
@RequestMapping("system/resource")
public class SysResourceController {
	private static final Log log = LogFactory.getLog(SysResourceController.class);
	
	@Autowired
	private IUResourceService resourceService;
	

	/**
	 * 整理
	 * @return
	 */
//	@ResponseBody
//	@RequestMapping(value="/arrangement",method=RequestMethod.GET)
//	public Object arrangement(){
//		JSONObject json = new JSONObject();
//		
//		new Thread(new UResourceThread()).start();
//		
//		json.put(SysConstants.Status.SUCCESS, true);
//		return json;
//	}
	
	/**
	 * 保存地址类资源
	 * @param uResource
	 * @param bindingResult
	 * @param request
	 * @return
	 * @throws Exception
	 */
	@ResponseBody
	@RequestMapping(value="/save", method=RequestMethod.PUT)
	public Object save(@RequestBody @Validated(value={ValidGroupSave.class}) UResource uResource, 
			BindingResult bindingResult, HttpServletRequest request) throws Exception {
		JSONObject json = new JSONObject();
		
		HttpSession session = request.getSession(false);
		String userId = (String) session.getAttribute(SysConstants.USER_ID);
		if(!bindingResult.hasErrors()){
			if(Assert.isValidString(userId) && Assert.isValidString(uResource.getResourceName()) 
					&& Assert.isValidString(uResource.getResourceIntroduction())
					&& Assert.isValidString(uResource.getSearchKeyWords())
					&& Assert.isValidString(uResource.getResourcePath())) {
				Date now = new Date();
				uResource.setCreateTime(now);
				uResource.setModifyTime(now);
				uResource.setDownloadAmount(0);
				uResource.setResourceAuthorId(userId);
				uResource.setResourceLength(0l);
				uResource.setResourceType(null);
				URI uri = new URI(uResource.getResourcePath(), false);
				String scheme = uri.getScheme();
				//0自己的资源，1其它网站地址如百度网盘分享地址，2电驴，3磁力，4迅雷
				if("http".equals(scheme) || "https".equals(scheme)){
					uResource.setPathType(1);
				}else if("ed2k".equals(scheme)){
					uResource.setPathType(2);
				}else if("magnet".equals(scheme)){
					uResource.setPathType(3);
				}else if("thunder".equals(scheme)){
					uResource.setPathType(4);
				}
				resourceService.save(uResource);
				json.put(SysConstants.Status.SUCCESS, true);
			}else {
				json.put(SysConstants.Status.SUCCESS, false);
				json.put(SysConstants.Status.RESULT, "文件或参数为空或用户没有登录");
			}
		}else {
			json.put(SysConstants.Status.SUCCESS, false);
			json.put(SysConstants.Status.RESULT, bindingResult.getAllErrors().get(0).getDefaultMessage());
		}
		
		log.debug(json);
		return json;
	}
	
	/**
	 * 上传资源
	 * @param resource
	 * @param introduction
	 * @param words
	 * @param words
	 * @param maxReadNum
	 * @return
	 * @throws Exception
	 */
	@ResponseBody
	@RequestMapping(value="/saveResource", method=RequestMethod.POST)
	public Object saveResource(MultipartFile resource, String introduction, String words, Integer maxReadNum, HttpServletRequest request) throws Exception {
		JSONObject json = new JSONObject();
		
		HttpSession session = request.getSession(false);
		String userId = (String) session.getAttribute(SysConstants.USER_ID);
		
		if(resource!=null && !resource.isEmpty() && Assert.isValidString(introduction) 
				&& Assert.isValidString(words) && Assert.isValidString(userId)) {
			long size = resource.getSize();
			String contentType = resource.getContentType();
			
			Date now = new Date();
			
			String root = SysConfig.getPath(SysConstants.Config.RESOURCE_ROOT);//根目录
			String dir = DateUtil.date2String(now, DateUtil.YYYYMMDD) + "/";//文件夹
			String filename = resource.getOriginalFilename();//原文件名
			String suffixName = FileUtil.getFileSuffix(filename);//后缀名
			
			String resourcePath = root + dir
					+ UUID.randomUUID().toString().replaceAll("-", "") + "."
					+ suffixName;
			
			File file = new File(resourcePath);
            FileUtil.makeFilePath(file);
            resource.transferTo(file);
			
			UResource uResource = new UResource();
			uResource.setCreateTime(now);
			uResource.setModifyTime(now);
			uResource.setDownloadAmount(0);
			uResource.setResourceName(filename);
			uResource.setResourceAuthorId(userId);
			uResource.setResourceIntroduction(introduction);
			uResource.setSearchKeyWords(words);
			uResource.setResourceLength(size);
			uResource.setResourceType(contentType);
			uResource.setResourcePath(resourcePath);
			uResource.setMaxReadNum(maxReadNum);
			uResource.setPathType(0);//0自己的资源，1其它网站地址如百度网盘分享地址，2电驴，3磁力，3迅雷
			
			resourceService.save(uResource);
			json.put(SysConstants.Status.SUCCESS, true);
		}else {
			json.put(SysConstants.Status.SUCCESS, false);
			json.put(SysConstants.Status.RESULT, "文件或参数为空或用户没有登录");
		}
		
		log.debug(json);
		return json;
	}
	
	/**
	 * 修改资源信息
	 * @param resourceId
	 * @param resourceName
	 * @param introduction
	 * @param words
	 * @return
	 * @throws Exception
	 */
	@ResponseBody
	@RequestMapping(value="/editResource", method=RequestMethod.POST)
	public Object editResource(String resourceId, String resourceName, String introduction, String words, String path, Integer maxReadNum) throws Exception {
		JSONObject json = new JSONObject();
		
		if(Assert.isValidString(resourceId) && Assert.isValidString(resourceName)
				 && Assert.isValidString(introduction) && Assert.isValidString(words)) {
			UResource resource = resourceService.findByPrimaryKey(resourceId);
    		if(resource!=null) {
    			if(resource.getPathType()!=0 && Assert.isInvalidString(path)) {
    				json.put(SysConstants.Status.SUCCESS, false);
    				json.put(SysConstants.Status.RESULT, "资源地址有误");
    			}else {
        			resource.setModifyTime(new Date());
    				resource.setResourceName(resourceName);
        			resource.setResourceIntroduction(introduction);
        			resource.setSearchKeyWords(words);
        			resource.setMaxReadNum(maxReadNum);
        			if(resource.getPathType()!=0) resource.setResourcePath(path);
        			resourceService.update(resource);
        			json.put(SysConstants.Status.SUCCESS, true);
    			}
    		}else {
    			json.put(SysConstants.Status.SUCCESS, false);
    			json.put(SysConstants.Status.RESULT, "资源不存在");
    		}
		}else {
			json.put(SysConstants.Status.SUCCESS, false);
			json.put(SysConstants.Status.RESULT, "参数有误");
		}
		
		log.debug(json);
		return json;
	}
	
    /**
     * 删除资源
     * @param resourceIdStr
     * @return
     * @throws Exception
     */
    @ResponseBody
	@RequestMapping(value="/removeResource/{resourceIdStr}",method=RequestMethod.DELETE)
    public Object removeResource(@PathVariable("resourceIdStr") String resourceIdStr) throws Exception {
    	JSONObject json = new JSONObject();
    	
    	if(Assert.isValidString(resourceIdStr)){
    		String[] resourceIds = resourceIdStr.split(SysConstants.Symbol.SEMICONLON);
    		resourceService.deleteByPrimaryKeys(resourceIds);
    		json.put(SysConstants.Status.SUCCESS, true);
    	}else {
    		json.put(SysConstants.Status.SUCCESS, false);
    		json.put(SysConstants.Status.RESULT, "参数有误");
    	}
    	
    	return json;
    }

	/**
	 * 分页查找
	 * @param search
	 * @param limit
	 * @param offset
	 * @param sort
	 * @param isDesc
	 * @param isOr
	 * @return
	 * @throws Exception
	 */
	@ResponseBody
	@RequestMapping(value="/getList",method=RequestMethod.GET)
	public Object getList(String search, Integer limit, Integer offset, 
			String sort, Boolean isDesc, Boolean isOr, Integer draw) throws Exception{
		JSONObject json = new JSONObject();
		
		UResourceQueryBean resourceQueryBean = new UResourceQueryBean();
		resourceQueryBean.setResourceName(search);
		resourceQueryBean.setSearchKeyWords(search);
		resourceQueryBean.setResourceIntroduction(search);
		
		resourceQueryBean.setLimit(limit==null?10:limit);
		resourceQueryBean.setOffset(offset==null?0:offset);
		resourceQueryBean.setOr(isOr==null?true:isOr);
		resourceQueryBean.setSort(sort==null?"createTime":sort);
		resourceQueryBean.setDesc(isDesc==null?true:isDesc);
		
		QueryBean<UResource> queryBean = resourceService.seniorQuery(resourceQueryBean);
		
		json.put(SysConstants.Status.SUCCESS, true);
		json.put(SysConstants.Status.RESULT, queryBean);
		json.put(SysConstants.Status.OTHER, draw);
//		json.put("draw", draw);
//		json.put("recordsTotal", queryBean.getItemCount());
//		json.put("recordsFiltered", queryBean.getItemCount());
//		json.put("data", queryBean.getResult());
		
		log.debug(json);
		return json;
	}
	
	/**
	 * 下载资源
	 * @param resourceId
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value="/download/{resourceId}", method=RequestMethod.GET)
    public String download(@PathVariable("resourceId") String resourceId) throws Exception{
		String path = "/WEB-INF/views/error/404.jsp";
    	if(Assert.isValidString(resourceId)){
    		UResource resource = resourceService.findByPrimaryKey(resourceId);
    		if(resource!=null && Assert.isValidString(resource.getResourcePath())) {
    			File file = new File(resource.getResourcePath());
    			if(file.exists()) {
	    			if(resource.getResourceLength() < 4194304) {//小于4M
	    				log.debug("下载 小 文件 ");
	    				path = "forward:/system/resource/down/"+resourceId;
	    			}else {//大于4M
	    				log.debug("下载 大 文件 ");
	    				path = "forward:/system/resource/downLargeRes/"+resourceId;
	    			}
    			}
    		}
    	}
    	return path;
    }
    
	
	/**
	 * 下载资源 文件过大时会内存溢出 FileUtils.readFileToByteArray(file)，一次性读取文件的，如果文件过大，可以考虑分批读取
	 * @param resourceId
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value="/down/{resourceId}", method=RequestMethod.GET)
    public ResponseEntity<byte[]> down(@PathVariable("resourceId") String resourceId) throws Exception{
    	ResponseEntity<byte[]> responseEntity = null;
    	if(Assert.isValidString(resourceId)){
    		UResource resource = resourceService.findByPrimaryKey(resourceId);
    		if(resource!=null && Assert.isValidString(resource.getResourcePath())) {
    			File file = new File(resource.getResourcePath());
    			if(file.exists()) {
	    			HttpHeaders headers = new HttpHeaders();
	    			String filename = resource.getResourceName();
	                headers.setContentDispositionFormData("attachment", URLEncoder.encode(filename, CharEncoding.UTF_8));
	                MediaType mediaType = MediaType.APPLICATION_OCTET_STREAM;
	                if(Assert.isValidString(resource.getResourceType())) {
	                	String types[] = resource.getResourceType().split("/");
	                	if(Assert.isValidArray(types) && types.length>1) {
	                		mediaType = new MediaType(types[0], types[1]);
	                	}
	                }
	                headers.setContentType(mediaType);
	                headers.setContentLength(resource.getResourceLength());
	                
	                //FileUtils.readFileToByteArray(file)，一次性读取文件的，如果文件过大，可以考虑分批读取
	                responseEntity = new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file), headers, HttpStatus.CREATED);
	                log.debug("下载文件 : “" + resource.getResourceName() + "”");
    			}
    		}
    	}
    	return responseEntity;
    }
    
    
    /**
     * 下载资源，文件过大 分批读取
     * @param resourceId
     * @param request
     * @param response
     * @throws Exception
     */
	@ResponseBody
    @RequestMapping(value="/downLargeRes/{resourceId}", method=RequestMethod.GET)
    public void downLargeRes(@PathVariable("resourceId") String resourceId, HttpServletResponse response) throws Exception{
    	
    	if(Assert.isValidString(resourceId)){
    		UResource resource = resourceService.findByPrimaryKey(resourceId);
    		if(resource!=null && Assert.isValidString(resource.getResourcePath())) {
    			File file = new File(resource.getResourcePath());
    			if(file.exists()) {
    				InputStream fis = new BufferedInputStream(new FileInputStream(file));
    				response.reset();
    				if(Assert.isValidString(resource.getResourceType())) {
    					response.setContentType(resource.getResourceType());
    				}else {
    					response.setContentType("application/octet-stream");
    				}
	    			String filename = resource.getResourceName();
	    			response.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(filename, CharEncoding.UTF_8));
	    			response.setHeader("Content-Length",resource.getResourceLength().toString());
    				OutputStream outStream = new BufferedOutputStream(response.getOutputStream());
    				byte[] buffer = new byte[4194304];//4M
                    int i = -1;
                    while ((i = fis.read(buffer)) != -1) {
                    	outStream.write(buffer, 0, i);
                    }
                    outStream.flush();
                    outStream.close();
                    fis.close();
                    response.flushBuffer();
    				
    				log.debug("下载文件 : “" + resource.getResourceName() + "”");
    			}
    		}
    	}
    }
    
}
